package com.yejiali.backend.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.yejiali.backend.common.apicode.ResponseCodeEnum;
import com.yejiali.backend.common.constant.SystemConstant;
import com.yejiali.backend.entity.CommentLike;
import com.yejiali.backend.entity.Comments;
import com.yejiali.backend.entity.Users;
import com.yejiali.backend.entity.Videos;
import com.yejiali.backend.entity.dto.CommentDTO;
import com.yejiali.backend.entity.dto.CommentReplyDTO;
import com.yejiali.backend.entity.vo.CommentReplyVO;
import com.yejiali.backend.entity.vo.CommentVO;
import com.yejiali.backend.entity.vo.MyTreeNode;
import com.yejiali.backend.mapper.CommentLikeMapper;
import com.yejiali.backend.mapper.CommentsMapper;
import com.yejiali.backend.mapper.UsersMapper;
import com.yejiali.backend.mapper.VideosMapper;
import com.yejiali.backend.response.Response;
import com.yejiali.backend.service.CommentsService;
import com.yejiali.backend.service.MentionsService;
import com.yejiali.backend.util.MessageUtil;
import com.yejiali.backend.util.RedisUtil;
import com.yejiali.backend.util.TreeUtils;
import com.yejiali.backend.ws.WebSocketServer;
import jakarta.websocket.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 评论表(Comments)表服务实现类
 *
 * @author yejiali
 * @since 2025-07-25 17:34:37
 */
@Service
public class CommentsServiceImpl extends ServiceImpl<CommentsMapper, Comments> implements CommentsService {


    @Autowired
    private UsersMapper usersMapper;

    @Autowired
    private VideosMapper videosMapper;

    @Autowired
    private CommentLikeMapper commentLikeMapper;

    @Autowired
    private TreeUtils treeUtils;

    @Autowired
    private RedisUtil redisUtil;


    /**
     * 根据视频ID查询评论(多级评论）
     * 查询最新评论
     * @param videoId 视频ID
     * @return
     */
    @Override
    public Response<List<CommentVO>> getCommentNewById(Long videoId) {
        //查询所有评论
        QueryWrapper<Comments> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("video_id", videoId);
        //时间倒序
        queryWrapper.orderByDesc("publish_time");
        List<Comments> comments = list(queryWrapper);
        List<CommentVO> commentVOList = toCommentList(comments);
        //构造成树
        MyTreeNode myTree = treeUtils.buildTree(commentVOList);
        //根节点为1的评论（一级评论）
        List<MyTreeNode> rootNodes = myTree.getChildren();
        List<CommentVO> rootCommentVOList = new ArrayList<>();
        for (MyTreeNode rootNode : rootNodes) {
            rootCommentVOList.add(rootNode.getContent());
        }
        return Response.success(rootCommentVOList);
    }

    /**
     * 根据视频ID查询评论（最热评论）
     * @param videoId 视频ID
     * @return
     */
    @Override
    public Response<List<CommentVO>> getCommentHotById(Long videoId, Long userId) {
        //查询所有评论
        QueryWrapper<Comments> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("video_id", videoId);
        queryWrapper.orderByDesc("like_count");
        List<Comments> comments = list(queryWrapper);
        List<CommentVO> commentVOList = toCommentList(comments);
        //查询点赞数
        for (CommentVO commentVO : commentVOList) {
            Long commentId = commentVO.getCommentId();
            String countKey = "comment:likeCount:" + commentId;
            //从Redis查询点赞数
            Object redisCount = redisUtil.get(countKey);
            //命中
            if (!Objects.isNull(redisCount)) {
                commentVO.setLikeCount(Long.parseLong(redisCount.toString()));
            } else {
                //未命中，查数据库同步到Redis
                QueryWrapper<CommentLike> queryWrapper1 = new QueryWrapper<>();
                queryWrapper1.eq("comment_id", commentId);
                Long dbCount = commentLikeMapper.selectCount(queryWrapper1);
                commentVO.setLikeCount(dbCount);
                redisUtil.set(countKey, dbCount);
            }
        }
        //用户登录状态（查询是否点赞）
        if (userId != null) {
            // 提取所有评论 ID
            List<Long> commentIds = commentVOList.stream()
                    .map(CommentVO::getCommentId)
                    .toList();
            // 从 Redis 中批量查询用户是否点赞 map id-是否点赞
            Map<Long, Boolean> likeStatusMap = new HashMap<>();
            for (Long commentId : commentIds) {
                String key = "comment:like:" + commentId;
                likeStatusMap.put(commentId, redisUtil.sHasKey(key, userId));
            }
            // 将未命中的评论 ID 提取出来
            List<Long> needQueryCommentIds = likeStatusMap.entrySet().stream()
                    .filter(item -> !item.getValue())
                    .map(Map.Entry::getKey)
                    .collect(Collectors.toList());
            // 从数据库中批量查询
            if (!needQueryCommentIds.isEmpty()) {
                QueryWrapper<CommentLike> queryWrapper1 = new QueryWrapper<>();
                queryWrapper1.in("comment_id", needQueryCommentIds);
                queryWrapper1.eq("user_id", userId);
                List<CommentLike> commentLikes = commentLikeMapper.selectList(queryWrapper1);
                for (CommentLike commentLike : commentLikes) {
                    likeStatusMap.put(commentLike.getCommentId(), true);
                    String key = "comment:like:" + commentLike.getCommentId();
                    redisUtil.sSet(key, userId);
                }
            }
            // 设置点赞状态
            for (CommentVO commentVO : commentVOList) {
                commentVO.setIsLiked(likeStatusMap.get(commentVO.getCommentId()));
            }
        }
        // 构造成树
        MyTreeNode myTree = treeUtils.buildTree(commentVOList);
        // 根节点为1的评论（一级评论）
        List<MyTreeNode> rootNodes = myTree.getChildren();
        List<CommentVO> rootCommentVOList = rootNodes.stream()
                .map(MyTreeNode::getContent)
                .collect(Collectors.toList());
        return Response.success(rootCommentVOList);
    }


    private List<CommentVO> toCommentList(List<Comments> rootComments) {
        List<CommentVO> commentVOs = BeanUtil.copyToList(rootComments, CommentVO.class);
        //遍历评论列表
        for (CommentVO commentVO : commentVOs) {
            //查询评论的发布者
            Users user = usersMapper.selectById(commentVO.getPublisherId());
            commentVO.setPublisherName(user.getNickname());
            commentVO.setAvatar(user.getAvatar());
        }
        return commentVOs;
    }

    /**
     * 新增评论
     * 将新增数据库记录插入后，给被回复的人发通知
     * 如果是一级评论则是该视频博主
     * 如果是二级评论则是被回复的人
     */
    @Override
    public Response<String> addComment(CommentDTO commentDTO) throws JsonProcessingException {
        //判断视频id是否有效
        Videos videos = videosMapper.selectById(commentDTO.getVideoId());
        if (videos == null) {
            return Response.error(ResponseCodeEnum.NOT_FOUND.getCode(),"视频不存在");
        }
        //判断发布者id是否有效
        Users user = usersMapper.selectById(commentDTO.getPublisherId());
        if (user == null) {
            return Response.error(ResponseCodeEnum.NOT_FOUND.getCode(),"用户不存在");
        }
        //封装数据
        Comments comment = BeanUtil.copyProperties(commentDTO, Comments.class);
        //查询接收者id
        //如果父级评论id为-1，则根据视频id查视频发布者id
        //如果有上一级评论，则根据评论id去找发布者id
        if(commentDTO.getParentCommentId() != -1) {
            //根据评论id去找发布者id
            Comments parentComment = getById(commentDTO.getParentCommentId());
            comment.setAccepterId(parentComment.getPublisherId());
        }
        save(comment);
        //给被回复的人发通知
        //发送消息
        String message = MessageUtil.getMessage(SystemConstant.SEND_REPLY_MESSAGE, comment.getPublisherId().toString(), "你被回复啦");
        ConcurrentHashMap<String, WebSocketServer> webSocketMap = WebSocketServer.getWebSocketMap();
        WebSocketServer webSocketServer = webSocketMap.get(comment.getAccepterId().toString());
        //是否在线
        if(webSocketServer!=null){
            try {
                Session session = webSocketServer.getSession();
                if(session!=null){
                    session.getBasicRemote().sendText(message);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        //不管是否在线都先存储未读数
        redisUtil.hincr("user:unread:"+comment.getAccepterId(),"replyMessage",1);
        return Response.success("评论写入成功");
    }


    /**
     * 查询回复我的评论
     * @param userId
     * @return
     */
    @Override
    public Response<CommentReplyDTO> replyComment(Long userId, Integer pageNum, Integer pageSize) {
        //判断id是否正确
        Users user = usersMapper.selectById(userId);
        if (user == null) {
            return Response.error(ResponseCodeEnum.NOT_FOUND.getCode(),"用户不存在");
        }
        //查询回复我的评论
        QueryWrapper<Comments> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("accepter_id", userId);
        //没有删除的通知
        queryWrapper.eq("message_deleted", 0);
        queryWrapper.orderByDesc("publish_time");
        //分页查询
        Page<Comments> page = new Page<>(pageNum, pageSize);
        IPage<Comments> commentPage = page(page, queryWrapper);
        List<Comments> comments = commentPage.getRecords();
        //封装对象
        List<CommentReplyVO> commentReplyVOS = BeanUtil.copyToList(comments, CommentReplyVO.class);
        for (CommentReplyVO commentReplyVO : commentReplyVOS) {
            //我是否点赞
            //判断是否点赞
            String key="comment:like:"+commentReplyVO.getCommentId();;
            Boolean isLike = redisUtil.sHasKey(key, userId);
            commentReplyVO.setIsLiked(isLike);
            //查询评论的发布者
            Users publisher = usersMapper.selectById(commentReplyVO.getPublisherId());
            commentReplyVO.setPublisherNickname(publisher.getNickname());
            commentReplyVO.setPublisherAvatar(publisher.getAvatar());
            //查询上级评论
            if(commentReplyVO.getParentCommentId() != -1){
                Comments parentComment = getById(commentReplyVO.getParentCommentId());
                commentReplyVO.setParentCommentContent(parentComment.getContent());
            }else{
                commentReplyVO.setPictureUrl(videosMapper.selectById(commentReplyVO.getVideoId()).getPictureUrl());
            }
        }
        return Response.success(new CommentReplyDTO(commentReplyVOS,commentPage.getTotal()));
    }

    /**
     * 逻辑删除回复我的评论的通知
     * @param commentId
     * @return
     */
    @Override
    public Response<String> deleteReplyComment(Long commentId) {
        //判断评论是否存在
        Comments comment = getById(commentId);
        if (comment == null ||comment.getMessageDeleted() == 1 || comment.getIsDeleted()==1 ){
            return Response.error(ResponseCodeEnum.NOT_FOUND.getCode(),"评论不存在或已删除");
        }
        comment.setMessageDeleted(1);
        updateById(comment);
        return Response.success("删除成功");
    }

    /**
     * 回复我的评论的回复
     * @param commentDTO
     * @return
     */
    @Override
    public Response<String> replyReplyComment(CommentDTO commentDTO) {
        //判断视频id是否有效
        Videos videos = videosMapper.selectById(commentDTO.getVideoId());
        if (videos == null) {
            return Response.error(ResponseCodeEnum.NOT_FOUND.getCode(),"视频不存在");
        }
        //判断发布者id是否有效
        Users sender = usersMapper.selectById(commentDTO.getPublisherId());
        Users accepter = usersMapper.selectById(commentDTO.getAccepterId());
        if (sender == null || accepter==null) {
            return Response.error(ResponseCodeEnum.NOT_FOUND.getCode(),"评论用户不存在");
        }
        //判断父级评论是否有效
        Comments parentComment = getById(commentDTO.getParentCommentId());
        if (parentComment == null) {
            return Response.error(ResponseCodeEnum.NOT_FOUND.getCode(),"父级评论不存在");
        }
        //封装数据
        Comments comment = BeanUtil.copyProperties(commentDTO, Comments.class);
        return Response.success("评论写入成功");
    }

}


